// Copyright 2009 Vladimir Solomenchuk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package net.aramzamzam.tapestry.judo.services.internal;

import net.aramzamzam.tapestry.judo.services.Require;
import net.aramzamzam.tapestry.judo.services.WidgetService;

import org.apache.tapestry5.ComponentResources;import org.apache.tapestry5.annotations.SetupRender;
import org.apache.tapestry5.internal.services.ComponentResourcesOperation;
import org.apache.tapestry5.model.MutableComponentModel;
import org.apache.tapestry5.services.ClassTransformation;
import org.apache.tapestry5.services.ComponentClassTransformWorker;
import org.apache.tapestry5.services.TransformConstants;



public class RequireWorker implements ComponentClassTransformWorker {

	private final WidgetService support;

	public RequireWorker(WidgetService support) {
		this.support = support;

	}

	@Override
	public void transform(ClassTransformation transformation,
			MutableComponentModel model) {
		Require annotation = transformation
				.getAnnotation(Require.class);
		if (annotation != null) {
			addOperationForStartupScripts(transformation, model, annotation.value());
		}
	}

	protected final void addOperationForStartupScripts(
			ClassTransformation transformation,
			final MutableComponentModel model, final String[] modules) {

		if (!model.getHandledRenderPhases().contains(SetupRender.class)) {
	        model.addRenderPhase(SetupRender.class);
	    }
		
		ComponentResourcesOperation op = new ComponentResourcesOperation() {
			// Remember that ONE instances of this op will be injected into
			// EVERY instance
			// of the component ... that means that we can't do any aggresive
			// caching
			// inside the operation (the operation must be threadsafe).

			public void perform(ComponentResources resources) {
				for (String module : modules)
					support.require(module);
			}
		};

		String opFieldName = transformation.addInjectedField(
				ComponentResourcesOperation.class, "operation", op);

		String resourcesName = transformation.getResourcesFieldName();

		String body = String.format("%s.perform(%s);", opFieldName,
				resourcesName);

		// This is what I like about this approach; the injected body is tiny.
		// The downside is that
		// the object that gets injected is hard to test, hard enough that we'll
		// just concentrate on
		// the integration test, thank you.

		transformation.extendMethod(TransformConstants.SETUP_RENDER_SIGNATURE,
				body);
	}

}
